package cn.edu.hitwh.kanlema.interceptor;

import cn.edu.hitwh.kanlema.constant.RedisConstants;
import cn.edu.hitwh.kanlema.constant.UserConstants;
import cn.edu.hitwh.kanlema.dto.Result;
import cn.edu.hitwh.kanlema.dto.UserDTO;
import cn.edu.hitwh.kanlema.util.RedisCache;
import cn.edu.hitwh.kanlema.util.UserHolder;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.http.server.PathContainer;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.util.pattern.PathPatternParser;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.Duration;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

@RequiredArgsConstructor
public class AuthInterceptor implements HandlerInterceptor {
    private final RedisCache redisCache;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getHeader(UserConstants.AUTH_HEADER);
        String tokenKey = null;
        UserDTO user = null;

        // 尝试获取登录信息
        if (!StrUtil.isBlank(token)) {
            tokenKey = RedisConstants.LOGIN_USER_KEY + token;
            user = redisCache.getObject(tokenKey, UserDTO.class);
        }

        // 检查是否必须登录
        PathPatternParser pathPatternParser = new PathPatternParser();
        if (
                Arrays.stream(UserConstants.NO_AUTH_PATH_PATTERNS)
                        .noneMatch(
                                pattern -> pathPatternParser.parse(pattern).matches(PathContainer.parsePath(request.getRequestURI()))
                        )
        ) {
            if (user == null) {
                response.setContentType("application/json;charset=utf-8");
                response.getWriter().write(JSONUtil.toJsonStr(Result.fail("未登录")));
                return false;
            }
        }

        if (user != null) {
            // 保存用户信息到 ThreadLocal
            UserHolder.saveUser(user);
            // 延长 token 有效期
            Duration ttl = redisCache.getExpire(tokenKey);
            if (ttl == null || ttl.compareTo(Duration.ofSeconds(RedisConstants.LOGIN_USER_TTL)) < 0) {
                redisCache.expire(tokenKey, RedisConstants.LOGIN_USER_TTL, TimeUnit.SECONDS);
            }
        }
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 移除用户信息
        UserHolder.removeUser();
    }
}
